import es
import random
import gamethread
import playerlib


import wcs

raceName = "Warden"
race     = wcs.races[raceName]

""" Load the strings into the variable text """
text     = race.loadStrings()

""" ############################### """
""" ### Begin the configuration ### """
""" ############################### """

config   = race.config()

raceMinLevel      = config.cvar("wardenMinLevel", 100, "The level required to player the Warden Race.")

config.text("")
config.text("******************************")
config.text("Hide")
config.text("   This skill allows the player to")
config.text("   become more invisible whilst")
config.text("   standing still.")
config.text("******************************")
config.text("")
hideMaxLevel      = config.cvar("hideMaxLevel",       2, "The maximum level of the hide skill") 
hideLevelInterval = config.cvar("hideLevelInterval",  5, "The intervals between the abilities to upgrade their Hide skill")

config.text("")
config.text("******************************")
config.text("Shadow Strike")
config.text("    This skill has a random chance")
config.text("    to poision a player when damaged.")
config.text("******************************")
config.text("")
shadowMaxLevel      = config.cvar("shadowMaxLevel",       3, "The maximum level of the Shadow Strike skill") 
shadowLevelInterval = config.cvar("shadowLevelInterval",  1, "The intervals between the abilities to upgrade their Shadow Strike skill")
shadowPercentage    = config.cvar("shadowPercentage",    10, "The chance the attacker will poision the victim multiplied via their Shadow Strike skill")

config.text("")
config.text("******************************")
config.text("Blink")
config.text("    This skill teleports a player")
config.text("    to the position he his looking.")
config.text("******************************")
config.text("")
blinkMaxLevel      = config.cvar("blinkMaxLevel",       3, "The maximum level of the blink skill") 
blinkLevelInterval = config.cvar("blinkLevelInterval",  2, "The intervals between the abilities to upgrade their Blink skill")

config.text("")
config.text("******************************")
config.text("Fan of Knives")
config.text("    This skill damages all nearby")
config.text("    enemies when the player presses")
config.text("    ability key.")
config.text("******************************")
config.text("")
fanMaxLevel      = config.cvar("fanMaxLevel",       3, "The maximum level of the Fan of Knives skill") 
fanLevelInterval = config.cvar("fanLevelInterval",  1, "The intervals between the abilities to upgrade their Fan of Knives skill")
fanCoolDown      = config.cvar("fanCoolDown",       8, "The amount of seconds after a player has used their Fan of Knives skill until they can use it again")

config.text("")
config.text("******************************")
config.text("Avatar of Vengance")
config.text("    This ultimate creates a sprite")
config.text("    on top of all the dead players")
config.text("    which Damage enemies.")
config.text("******************************")
config.text("")
avatarMinLevel      = config.cvar("avatarMinLevel",       6, "The level required before a player can acquire level 1 of the Avatar of Vengance skill.")
avatarMaxLevel      = config.cvar("avatarMaxLevel",       1, "The maximum level of the Avatar of Vengance skill") 
avatarLevelInterval = config.cvar("avatarLevelInterval",  1, "The intervals between the abilities to upgrade their Avatar of Vengance skill")
avatarCoolDown      = config.cvar("avatarCoolDown",      30, "The amount of seconds after a player has used their Avatar of Vengance skill until they can use it again")

config.load(True)

""" ##################### """
""" ### END OF CONFIG ### """
""" ##################### """

race.registerSkill("Hide",                  int(hideMaxLevel),   int(hideLevelInterval),   "You become hard to see when standing still.")
race.registerSkill("Shadow Strike",         int(shadowMaxLevel), int(shadowLevelInterval), "Your attacks deal extra damage over time.")
race.registerSkill("Fan of Knives",         int(fanMaxLevel),    int(fanLevelInterval),    "Use your +ability key to deal damage to all oppents near you.")
race.registerSkill("Blink",                 int(blinkMaxLevel),  int(blinkLevelInterval),  "Use your +ability2 key to jump to the postion you are looking at.")
race.registerUltimate("Avatar of Vengance", int(avatarMinLevel), int(avatarMaxLevel),      int(avatarLevelInterval), "Creates an avatar that summon's spirit allies from near by corpses.")
race.registerMinLevel(int(raceMinLevel))

def player_ultimate_on(event_var):
    """
    Executed when a player's ultimate is activated. Create the first spirit.
    """
    userid = int(event_var["userid"])
    player = wcs.players[userid]
    if player[raceName]["Avatar of Vengance"]:
        x, y, z = es.getplayerlocation(userid)
        player.setCoolDown("Avatar of Vengance", int(avatarCoolDown))
        createSpirit(userid, x, y, z, 0, [])

def createSpirit(userid, x, y, z, count, bannedlist):
    """
    Creates a spirit which will turn a random dead player in range into a
    spirit causing it to attack random enemies.
    
    @param int userid The ID of the user the spirit will belong to
    @param float x The x coord of the dead range origin
    @param float y The y coord of the dead range origin
    @param float z The z coord of the dead range origin
    @param int count The current count used to count how many loops have executed
    @param list bannedList Who is banned from the dead list
    """
    if count < 20:
        nearlist = filter(lambda x: x not in bannedlist, deadnear(x, y, z))
        if nearlist:
            post = random.choice(nearlist)
            bannedlist.append(post)
            spiritLoop(userid, post[0], post[1], post[2] + 30, 0)
            wcs.players[userid].delayed(1, createSpirit,(userid, x, y, z, count + 1, bannedlist))
            
def spiritLoop(userid, x, y, z, count):
    """
    Any player within an 800 range box of the spirit will be damaged for 15
    health. Ensure that we loop through all enemies within range of the spirit
    and damage them all.
    
    @param int userid The ID of the user that owns the spirit
    @param float x The x coord of the spirit origin
    @param float y The y coord of the spirit origin
    @param float z The z coord of the spirit origin
    @param int count The amount of iterations the loop has gone through
    """
    player = wcs.players[userid]
    if count <= 10:
        player.delayed(.5, spiritLoop, (userid, x, y, z, count + 1))
        userlist = player.getNearCoordList(x, y, z, 800, 800, 800, "#ct" if es.getplayerteam(userid) == 2 else "#t")
        if userlist:
            target = random.choice(userlist)
            wcs.players[target].damage(15, 32, userid)
            
def deadnear(x, y, z):
    """
    Gets a list of dead players in a 1,000 range of a ceratin x, y, z coords.
    
    @param float x The x coord of the origin
    @param float y The y coord of the origin
    @param float z The z coord of the origin
    @return list List of dead locations in range of the origin
    """
    nearlist = []
    for player in es.getUseridList():
        location = wcs.players[player]["death location"]
        if location:
            target_x, target_y, target_z = location
            if target_x or target_y or target_z:
                target_x -= x
                target_y -= y
                target_z -= z
                if abs(target_x) <= 1000 and abs(target_y) <= 1000 and abs(target_z) <= 1000:
                    nearlist.append(tuple(target_x, target_y, target_z))
    return nearlist
    
def player_death(event_var):
    """
    Executed when a player dies, update their last death location
    """
    userid = int(event_var["userid"])
    wcs.players[userid]["death location"] = es.getplayerlocation(userid)

def player_hurt(event_var):
    """
    Executed when a player is damaged, if the attacker has Shadow Strike skill,
    then make a random chance of poisioning the victim if they're not already
    poisoned.
    """
    userid   = int(event_var["userid"])
    attacker = int(event_var["attacker"])
    damage   = wcs.getDamage(event_var)
    if not damage:
        return
    strike = wcs.players[attacker][raceName]["Shadow Strike"] * int(shadowPercentage)
    if random.randint(1, 100) <= strike:
        player = wcs.players[userid]
        if not player["poisoned"]:
            #wcs.effects.Beam1(attacker,userid,1.5,0,255,0)
            player["poisoned"] = True
            player.speedAdd(-0.2)
            for i in xrange(5):
                delay = (i + 1) * 2
                player.delayed(delay, player.damage, (damage/10, 32, attacker))
            player.delayed(10, player.speedAdd, 0.2)
            player.delayed(10, player.__delitem__, "poisoned")

def player_spawn(event_var):
    """
    Executed when a player spawns, test to see if the player has a hide skill,
    if so, then begin the check for hiding the player
    """
    userid = int(event_var["userid"])
    player = wcs.players[userid]
    del player["dead location"]
    hide = player[raceName]["Hide"] * 40
    if hide:
        player["location"] = es.getplayerlocation(userid)
        if not player["looping"]:
            hideLoop(userid, 165 - hide)
            
def player_ability_on(event_var):
    """
    Executed when a player activates their +ability key. If they have a fan
    of knives skill, then damage all nearby players.
    """
    userid = int(event_var["userid"])
    player = wcs.players[userid]
    fan = player[raceName]["Fan of Knives"]
    if fan:
        cooldown = player.getCoolDown("Fan of Knives")
        if not cooldown:
            fanSkill(userid)
        else:
            es.tell(userid, "#multi", text("cooldown", {"time": cooldown, "skill" : "Fan of Knives"}, playerlib.getPlayer(userid).get("lang")))
            
def player_ability_on2(event_var):
    """
    Executed when the player presses their +ability2 key. If they have a blink
    skill, then make sure we teleport them.
    """
    userid = int(event_var["userid"])
    player = wcs.players[userid]
    blink  = player[raceName]["Blink"]
    if blink:
        cooldown = player.getCoolDown("Blink") 
        if not cooldown:
            x, y, z = player.getViewCoord()
            player.pushTo(x, y, z, 5)
            player.setCoolDown("Blink", 30 / blink)
        else:
            es.tell(userid, "#multi", text("cooldown", {"time": cooldown, "skill" : "Blink"}, playerlib.getPlayer(userid).get("lang")))

def fanSkill(userid):
    """
    Executed when we wish to damage all nearby players, execute the near command
    
    @param int userid The ID of the user who will cause the damage
    """
    #wcs.effect.Ring3(userid, 360, 1, 128, 128, 128)
    player = wcs.players[userid]
    team = es.getplayerteam(userid)
    player.setCoolDown("Fan of Knives", int(fanCoolDown))
    player.near(360, knives, "#ct" if team == 2 else "#t")
	
def knives(userid, attacker):
    """
    This is executed for every player in range of the attacker when the Fan of
    Knives spell is used, damage the players.
    
    @param int userid The ID of the user to damage
    @param itn attacker The ID of the attacker who is causing the damage
    """
    level = wcs.players[attacker][raceName]["Fan of Knives"]
    wcs.players[userid].damage(level * 35, 32, attacker)
    
def hideLoop(userid, alpha):
    """
    Executed every second to see if a user has moved. If they have been
    stationary, then begin a fade over 2 seconds. Once they move, create a 0.5
    second fade out time.
    
    @param int userid The ID of the user to check for fading
    @param int alpha The alpha to fade to.
    """
    player = wcs.players[userid]
    if not es.getplayerprop(userid, "CBasePlayer.pl.deadflag"):
        del player["looping"]
    player["looping"] = True
    location = es.getplayerlocation(userid)
    if location == player["location"]:
        player.fade(alpha, 2)
    else:
        player.fade(255, 0.5)
        player["location"] = location
    gamethread.delayed(1, hideLoop, (userid, alpha))